package main

import (
	"database/sql"
	"encoding/json"
	"reflect"

	"test.com/fusion"
	"test.com/worlddb"
)

type sobjSpawnDialogTableRow struct {
	SpawnID uint32  `json:"spawnId"`
	Entry   uint32  `json:"entry"`
	MapID   uint32  `json:"map_id"`
	MapType uint32  `json:"map_type"`
	X       float32 `json:"x"`
	Y       float32 `json:"y"`
	Z       float32 `json:"z"`
}

func getAllSObjSpawn4DialogTable(db *sql.DB) ([]*sobjSpawnDialogTableRow, error) {
	var sobjSpawnRows []*sobjSpawnDialogTableRow
	rows, err := db.Query("SELECT `spawnId`,`entry`,`map_id`,`map_type`," +
		"`x`,`y`,`z` FROM `staticobject_spawn`")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	for rows.Next() {
		var sobjSpawnRow sobjSpawnDialogTableRow
		err = rows.Scan(&sobjSpawnRow.SpawnID, &sobjSpawnRow.Entry,
			&sobjSpawnRow.MapID, &sobjSpawnRow.MapType,
			&sobjSpawnRow.X, &sobjSpawnRow.Y, &sobjSpawnRow.Z)
		if err == nil {
			sobjSpawnRows = append(sobjSpawnRows, &sobjSpawnRow)
		} else {
			return nil, err
		}
	}
	return sobjSpawnRows, nil
}

type sobjProtoDialogTableRow struct {
	SobjTypeId uint32 `json:"sobjTypeId"`
	LootSetID  uint32 `json:"lootSetID"`
}

func getAllSObjProto4DialogTable(db *sql.DB) ([]*sobjProtoDialogTableRow, error) {
	var sobjProtoRows []*sobjProtoDialogTableRow
	rows, err := db.Query("SELECT `sobjTypeId`,`lootSetID` FROM `sobj_prototype`")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	for rows.Next() {
		var sobjProtoRow sobjProtoDialogTableRow
		err = rows.Scan(&sobjProtoRow.SobjTypeId, &sobjProtoRow.LootSetID)
		if err == nil {
			sobjProtoRows = append(sobjProtoRows, &sobjProtoRow)
		} else {
			return nil, err
		}
	}
	return sobjProtoRows, nil
}

func getAllSObjNames(db *sql.DB) (map[uint32]string, error) {
	return getAllKeyI18Ns(db,
		"sobj_prototype", "sobjTypeId", worlddb.STRING_TEXT_TYPE_SOBJ_NAME)
}

func getSObjInfo(db *sql.DB, sobjTypeId uint32) (*worlddb.SObjPrototype, error) {
	var sobjInfo *worlddb.SObjPrototype
	sobjInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(sobjInfo), "`sobjTypeId`=?", sobjTypeId)
	if err != nil {
		return nil, err
	}
	if sobjInfoVals.Len() < 1 {
		return nil, sql.ErrNoRows
	}
	return sobjInfoVals.Index(0).Interface().(*worlddb.SObjPrototype), nil
}

func getSObjInstanceJsonData(db *sql.DB, sobjTypeId uint32) ([]byte, error) {
	var err error
	var sobjProto sobjWebPrototype
	sobjProto.SObjName, err =
		getI18N(db, worlddb.STRING_TEXT_TYPE_SOBJ_NAME, sobjTypeId)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}
	sobjProto.SObjDesc, err =
		getI18N(db, worlddb.STRING_TEXT_TYPE_SOBJ_DESC, sobjTypeId)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}
	sobjProto.SObjInfo, err = getSObjInfo(db, sobjTypeId)
	if err != nil {
		return nil, err
	}
	sobjData, err := json.Marshal(
		fusion.MarshalEntityToInterface(&sobjProto, "json"))
	if err != nil {
		return nil, err
	}
	return sobjData, nil
}

func newSObjInstance(tx *sql.Tx, sobjName, sobjDesc string) (uint32, error) {
	sobjInfo := worlddb.SObjPrototype{}
	sobjTypeId, err := fusion.SaveJsontableToDB(tx, &sobjInfo)
	if err != nil {
		return 0, err
	}
	err = setI18Ns(tx,
		worlddb.STRING_TEXT_TYPE_SOBJ_NAME, sobjTypeId, sobjName,
		worlddb.STRING_TEXT_TYPE_SOBJ_DESC, sobjTypeId, sobjDesc)
	if err != nil {
		return 0, err
	}
	return sobjTypeId, nil
}

func copySObjInstance(db *sql.DB, tx *sql.Tx, sobjTypeId uint32) (uint32, error) {
	var sobjInfo *worlddb.SObjPrototype
	sobjInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(sobjInfo), "`sobjTypeId`=?", sobjTypeId)
	if err != nil {
		return 0, err
	}
	if sobjInfoVals.Len() < 1 {
		return 0, sql.ErrNoRows
	}
	sobjInfo = sobjInfoVals.Index(0).Interface().(*worlddb.SObjPrototype)
	sobjInfo.SobjTypeId = 0
	ID, err := fusion.SaveJsontableToDB(tx, sobjInfo)
	if err != nil {
		return 0, err
	}
	err = copyI18Ns(db, tx,
		worlddb.STRING_TEXT_TYPE_SOBJ_NAME, sobjTypeId, ID,
		worlddb.STRING_TEXT_TYPE_SOBJ_DESC, sobjTypeId, ID)
	if err != nil {
		return 0, err
	}
	return ID, nil
}

func deleteSObjInstance(tx *sql.Tx, sobjTypeId uint32) error {
	_, err := tx.Exec(
		"DELETE FROM `sobj_prototype` WHERE `sobjTypeId`=?", sobjTypeId)
	if err != nil {
		return err
	}
	return nil
}

func saveSObjInstance(tx *sql.Tx, sobjProto *SObjPrototype) error {
	err := setI18Ns(tx,
		worlddb.STRING_TEXT_TYPE_SOBJ_NAME,
		sobjProto.SObjInfo.SobjTypeId, sobjProto.SObjName,
		worlddb.STRING_TEXT_TYPE_SOBJ_DESC,
		sobjProto.SObjInfo.SobjTypeId, sobjProto.SObjDesc)
	if err != nil {
		return err
	}
	_, err = fusion.SaveJsontableToDB(tx, sobjProto.SObjInfo)
	if err != nil {
		return err
	}
	return nil
}
